home *** CD-ROM | disk | FTP | other *** search
/ Programming Windows (5th Edition) / Programming Windows, 5th ed. - Companion CD (097-0002183)(1999).iso / Chap23 / NetTime / NetTime.c next >
Encoding:
C/C++ Source or Header  |  1998-10-09  |  13.8 KB  |  403 lines

  1. /*-------------------------------------------------------
  2.    NETTIME.C -- Sets System Clock from Internet Services
  3.                 (c) Charles Petzold, 1998
  4.   -------------------------------------------------------*/
  5.  
  6. #include <windows.h>
  7. #include "resource.h"
  8.  
  9. #define WM_SOCKET_NOTIFY (WM_USER + 1)
  10. #define ID_TIMER         1
  11.  
  12. LRESULT CALLBACK WndProc   (HWND, UINT, WPARAM, LPARAM) ;
  13. BOOL    CALLBACK MainDlg   (HWND, UINT, WPARAM, LPARAM) ;
  14. BOOL    CALLBACK ServerDlg (HWND, UINT, WPARAM, LPARAM) ;
  15.  
  16. void ChangeSystemTime (HWND hwndEdit, ULONG ulTime) ;
  17. void FormatUpdatedTime (HWND hwndEdit, SYSTEMTIME * pstOld, 
  18.                                        SYSTEMTIME * pstNew) ;
  19. void EditPrintf (HWND hwndEdit, TCHAR * szFormat, ...) ;
  20.  
  21. HINSTANCE hInst ;
  22. HWND      hwndModeless ;
  23.  
  24. int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
  25.                     PSTR szCmdLine, int iCmdShow)
  26. {
  27.      static TCHAR szAppName[] = TEXT ("NetTime") ;
  28.      HWND         hwnd ;
  29.      MSG          msg ;
  30.      RECT         rect ;
  31.      WNDCLASS     wndclass ;
  32.  
  33.      hInst = hInstance ;
  34.  
  35.      wndclass.style         = 0 ;
  36.      wndclass.lpfnWndProc   = WndProc ;
  37.      wndclass.cbClsExtra    = 0 ;
  38.      wndclass.cbWndExtra    = 0 ;
  39.      wndclass.hInstance     = hInstance ;
  40.      wndclass.hIcon         = LoadIcon (NULL, IDI_APPLICATION) ;
  41.      wndclass.hCursor       = NULL ;
  42.      wndclass.hbrBackground = NULL ;
  43.      wndclass.lpszMenuName  = NULL ;
  44.      wndclass.lpszClassName = szAppName ;
  45.  
  46.      if (!RegisterClass (&wndclass))
  47.      {
  48.           MessageBox (NULL, TEXT ("This program requires Windows NT!"), 
  49.                       szAppName, MB_ICONERROR) ;
  50.           return 0 ;
  51.      }
  52.      
  53.      hwnd = CreateWindow (szAppName, TEXT ("Set System Clock from Internet"),
  54.                           WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU |
  55.                                WS_BORDER | WS_MINIMIZEBOX,
  56.                           CW_USEDEFAULT, CW_USEDEFAULT,
  57.                           CW_USEDEFAULT, CW_USEDEFAULT,
  58.                           NULL, NULL, hInstance, NULL) ;
  59.  
  60.           // Create the modeless dialog box to go on top of the window
  61.  
  62.      hwndModeless = CreateDialog (hInstance, szAppName, hwnd, MainDlg) ;
  63.  
  64.           // Size the main parent window to the size of the dialog box.  
  65.           //   Show both windows.
  66.  
  67.      GetWindowRect (hwndModeless, &rect) ;
  68.      AdjustWindowRect (&rect, WS_CAPTION | WS_BORDER, FALSE) ;
  69.  
  70.      SetWindowPos (hwnd, NULL, 0, 0, rect.right - rect.left,
  71.                    rect.bottom - rect.top, SWP_NOMOVE) ;
  72.  
  73.      ShowWindow (hwndModeless, SW_SHOW) ;     
  74.      ShowWindow (hwnd, iCmdShow) ;
  75.      UpdateWindow (hwnd) ;
  76.  
  77.           // Normal message loop when a modeless dialog box is used.
  78.  
  79.      while (GetMessage (&msg, NULL, 0, 0))
  80.      {
  81.           if (hwndModeless == 0 || !IsDialogMessage (hwndModeless, &msg))
  82.           {
  83.                TranslateMessage (&msg) ;
  84.                DispatchMessage (&msg) ;
  85.           }
  86.      }
  87.      return msg.wParam ;
  88. }
  89.  
  90. LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  91. {
  92.      switch (message)
  93.      {
  94.      case WM_SETFOCUS:
  95.           SetFocus (hwndModeless) ;
  96.           return 0 ;
  97.  
  98.      case WM_DESTROY:
  99.           PostQuitMessage (0) ;
  100.           return 0 ;
  101.      }
  102.      return DefWindowProc (hwnd, message, wParam, lParam) ;
  103. }
  104.  
  105. BOOL CALLBACK MainDlg (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  106. {
  107.      static char   szIPAddr[32] = { "132.163.135.130" } ;
  108.      static HWND   hwndButton, hwndEdit ;
  109.      static SOCKET sock ;
  110.      static struct sockaddr_in sa ;
  111.      static TCHAR  szOKLabel[32] ;
  112.      int           iError, iSize ;
  113.      unsigned long ulTime ;
  114.      WORD          wEvent, wError ;
  115.      WSADATA       WSAData ;     
  116.  
  117.      switch (message)
  118.      {
  119.      case WM_INITDIALOG:
  120.           hwndButton = GetDlgItem (hwnd, IDOK) ;
  121.           hwndEdit = GetDlgItem (hwnd, IDC_TEXTOUT) ;
  122.           return TRUE ;
  123.  
  124.      case WM_COMMAND:
  125.           switch (LOWORD (wParam))
  126.           {
  127.           case IDC_SERVER:
  128.                DialogBoxParam (hInst, TEXT ("Servers"), hwnd, ServerDlg, 
  129.                                (LPARAM) szIPAddr) ;
  130.                return TRUE ;
  131.  
  132.           case IDOK:
  133.                     // Call "WSAStartup" and display description text
  134.  
  135.                if (iError = WSAStartup (MAKEWORD(2,0), &WSAData))
  136.                {
  137.                     EditPrintf (hwndEdit, TEXT ("Startup error #%i.\r\n"), 
  138.                                           iError) ;
  139.                     return TRUE ;
  140.                }
  141.                EditPrintf (hwndEdit, TEXT ("Started up %hs\r\n"), 
  142.                                      WSAData.szDescription);
  143.  
  144.                     // Call "socket"
  145.  
  146.                sock = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP) ;
  147.  
  148.                if (sock == INVALID_SOCKET)
  149.                {
  150.                     EditPrintf (hwndEdit, 
  151.                                 TEXT ("Socket creation error #%i.\r\n"), 
  152.                                 WSAGetLastError ()) ;
  153.                     WSACleanup () ;
  154.                     return TRUE ;
  155.                }
  156.                EditPrintf (hwndEdit, TEXT ("Socket %i created.\r\n"), sock) ;
  157.  
  158.                     // Call "WSAAsyncSelect" 
  159.  
  160.                if (SOCKET_ERROR == WSAAsyncSelect (sock, hwnd, WM_SOCKET_NOTIFY, 
  161.                                                    FD_CONNECT | FD_READ))
  162.                {
  163.                     EditPrintf (hwndEdit, 
  164.                                 TEXT ("WSAAsyncSelect error #%i.\r\n"),
  165.                                 WSAGetLastError ()) ;
  166.                     closesocket (sock) ;
  167.                     WSACleanup () ;
  168.                     return TRUE ;
  169.                }
  170.  
  171.                     // Call "connect" with IP address and time-server port
  172.  
  173.                sa.sin_family           = AF_INET ;
  174.                sa.sin_port             = htons (IPPORT_TIMESERVER) ; 
  175.                sa.sin_addr.S_un.S_addr = inet_addr (szIPAddr) ;
  176.  
  177.                connect(sock, (SOCKADDR *) &sa, sizeof (sa)) ;
  178.  
  179.                     // "connect" will return SOCKET_ERROR because even if it
  180.                     // succeeds, it will require blocking. The following only
  181.                     // reports unexpected errors.
  182.  
  183.                if (WSAEWOULDBLOCK != (iError = WSAGetLastError ()))
  184.                {
  185.                     EditPrintf (hwndEdit, TEXT ("Connect error #%i.\r\n"), 
  186.                                           iError) ;
  187.                     closesocket (sock) ;
  188.                     WSACleanup () ;
  189.                     return TRUE ;
  190.                }
  191.                EditPrintf (hwndEdit, TEXT ("Connecting to %hs..."), szIPAddr) ;
  192.      
  193.                     // The result of the "connect" call will be reported 
  194.                     // through the WM_SOCKET_NOTIFY message.
  195.                     // Set timer and change the button to "Cancel"
  196.  
  197.                SetTimer (hwnd, ID_TIMER, 1000, NULL) ;
  198.                GetWindowText (hwndButton, szOKLabel, sizeof (szOKLabel) /
  199.                                                      sizeof (TCHAR)) ;
  200.                SetWindowText (hwndButton, TEXT ("Cancel")) ;
  201.                SetWindowLong (hwndButton, GWL_ID, IDCANCEL) ;
  202.                return TRUE ;
  203.  
  204.           case IDCANCEL:
  205.                closesocket (sock) ;
  206.                sock = 0 ;
  207.                WSACleanup () ;
  208.                SetWindowText (hwndButton, szOKLabel) ;
  209.                SetWindowLong (hwndButton, GWL_ID, IDOK) ;
  210.  
  211.                KillTimer (hwnd, ID_TIMER) ;
  212.                EditPrintf (hwndEdit, TEXT ("\r\nSocket closed.\r\n")) ;
  213.                return TRUE ;
  214.  
  215.           case IDC_CLOSE:
  216.                if (sock)
  217.                     SendMessage (hwnd, WM_COMMAND, IDCANCEL, 0) ;
  218.  
  219.                DestroyWindow (GetParent (hwnd)) ;
  220.                return TRUE ;
  221.           }
  222.           return FALSE ;
  223.  
  224.      case WM_TIMER:
  225.           EditPrintf (hwndEdit, TEXT (".")) ;
  226.           return TRUE ;
  227.  
  228.      case WM_SOCKET_NOTIFY:
  229.           wEvent = WSAGETSELECTEVENT (lParam) ;   // ie, LOWORD
  230.           wError = WSAGETSELECTERROR (lParam) ;   // ie, HIWORD
  231.  
  232.                // Process two events specified in WSAAsyncSelect
  233.  
  234.           switch (wEvent)
  235.           {
  236.                // This event occurs as a result of the "connect" call
  237.  
  238.           case FD_CONNECT:
  239.                EditPrintf (hwndEdit, TEXT ("\r\n")) ;
  240.  
  241.                if (wError)
  242.                {
  243.                     EditPrintf (hwndEdit, TEXT ("Connect error #%i."), 
  244.                                           wError) ;
  245.                     SendMessage (hwnd, WM_COMMAND, IDCANCEL, 0) ;
  246.                     return TRUE ;
  247.                }
  248.                EditPrintf (hwndEdit, TEXT ("Connected to %hs.\r\n"), szIPAddr) ;
  249.  
  250.                     // Try to receive data. The call will generate an error
  251.                     // of WSAEWOULDBLOCK and an event of FD_READ
  252.  
  253.                recv (sock, (char *) &ulTime, 4, MSG_PEEK) ;
  254.                EditPrintf (hwndEdit, TEXT ("Waiting to receive...")) ;
  255.                return TRUE ;
  256.  
  257.                     // This even occurs when the "recv" call can be made
  258.                
  259.           case FD_READ:
  260.                KillTimer (hwnd, ID_TIMER) ;
  261.                EditPrintf (hwndEdit, TEXT ("\r\n")) ;
  262.  
  263.                if (wError)
  264.                {
  265.                     EditPrintf (hwndEdit, TEXT ("FD_READ error #%i."), 
  266.                                           wError) ;
  267.                     SendMessage (hwnd, WM_COMMAND, IDCANCEL, 0) ;
  268.                     return TRUE ;
  269.                }
  270.                     // Get the time and swap the bytes
  271.  
  272.                iSize = recv (sock, (char *) &ulTime, 4, 0) ;
  273.                ulTime = ntohl (ulTime) ;
  274.                EditPrintf (hwndEdit, 
  275.                            TEXT ("Received current time of %u seconds ")
  276.                            TEXT ("since Jan. 1 1900.\r\n"), ulTime) ;
  277.  
  278.                     // Change the system time
  279.      
  280.                ChangeSystemTime (hwndEdit, ulTime) ;
  281.                SendMessage (hwnd, WM_COMMAND, IDCANCEL, 0) ;
  282.                return TRUE ;
  283.           }
  284.           return FALSE ;
  285.      }
  286.      return FALSE ;
  287. }
  288.  
  289. BOOL CALLBACK ServerDlg (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  290. {
  291.      static char * szServer ;
  292.      static WORD   wServer = IDC_SERVER1 ;
  293.      char          szLabel [64] ;
  294.  
  295.      switch (message)
  296.      {
  297.      case WM_INITDIALOG:
  298.           szServer = (char *) lParam ;
  299.           CheckRadioButton (hwnd, IDC_SERVER1, IDC_SERVER10, wServer) ;
  300.           return TRUE ;
  301.  
  302.      case WM_COMMAND:
  303.           switch (LOWORD (wParam))
  304.           {
  305.           case IDC_SERVER1:
  306.           case IDC_SERVER2:
  307.           case IDC_SERVER3:
  308.           case IDC_SERVER4:
  309.           case IDC_SERVER5:
  310.           case IDC_SERVER6:
  311.           case IDC_SERVER7:
  312.           case IDC_SERVER8:
  313.           case IDC_SERVER9:
  314.           case IDC_SERVER10:
  315.                wServer = LOWORD (wParam) ;
  316.                return TRUE ;
  317.  
  318.           case IDOK:
  319.                GetDlgItemTextA (hwnd, wServer, szLabel, sizeof (szLabel)) ;
  320.                strtok (szLabel, "(") ;
  321.                strcpy (szServer, strtok (NULL, ")")) ;
  322.                EndDialog (hwnd, TRUE) ;
  323.                return TRUE ;
  324.  
  325.           case IDCANCEL:
  326.                EndDialog (hwnd, FALSE) ;
  327.                return TRUE ;
  328.           }
  329.           break ;
  330.      }
  331.      return FALSE ;
  332. }
  333.  
  334. void ChangeSystemTime (HWND hwndEdit, ULONG ulTime)
  335. {
  336.      FILETIME      ftNew ;
  337.      LARGE_INTEGER li ;
  338.      SYSTEMTIME    stOld, stNew ;
  339.  
  340.      GetLocalTime (&stOld) ;
  341.  
  342.      stNew.wYear         = 1900 ;
  343.      stNew.wMonth        = 1 ;
  344.      stNew.wDay          = 1 ;
  345.      stNew.wHour         = 0 ;
  346.      stNew.wMinute       = 0 ;
  347.      stNew.wSecond       = 0 ;
  348.      stNew.wMilliseconds = 0 ;
  349.  
  350.      SystemTimeToFileTime (&stNew, &ftNew) ;
  351.      li = * (LARGE_INTEGER *) &ftNew ;
  352.      li.QuadPart += (LONGLONG) 10000000 * ulTime ; 
  353.      ftNew = * (FILETIME *) &li ;
  354.      FileTimeToSystemTime (&ftNew, &stNew) ;
  355.  
  356.      if (SetSystemTime (&stNew))
  357.      {
  358.           GetLocalTime (&stNew) ;
  359.           FormatUpdatedTime (hwndEdit, &stOld, &stNew) ;
  360.      }
  361.      else
  362.           EditPrintf (hwndEdit, TEXT ("Could NOT set new date and time.")) ;
  363. }
  364.  
  365. void FormatUpdatedTime (HWND hwndEdit, SYSTEMTIME * pstOld, SYSTEMTIME * pstNew)
  366. {
  367.      TCHAR szDateOld [64], szTimeOld [64], szDateNew [64], szTimeNew [64] ;
  368.  
  369.      GetDateFormat (LOCALE_USER_DEFAULT, LOCALE_NOUSEROVERRIDE | DATE_SHORTDATE,
  370.                     pstOld, NULL, szDateOld, sizeof (szDateOld)) ;
  371.      
  372.      GetTimeFormat (LOCALE_USER_DEFAULT, LOCALE_NOUSEROVERRIDE | 
  373.                          TIME_NOTIMEMARKER | TIME_FORCE24HOURFORMAT,
  374.                     pstOld, NULL, szTimeOld, sizeof (szTimeOld)) ;
  375.  
  376.      GetDateFormat (LOCALE_USER_DEFAULT, LOCALE_NOUSEROVERRIDE | DATE_SHORTDATE,
  377.                     pstNew, NULL, szDateNew, sizeof (szDateNew)) ;
  378.      
  379.      GetTimeFormat (LOCALE_USER_DEFAULT, LOCALE_NOUSEROVERRIDE | 
  380.                          TIME_NOTIMEMARKER | TIME_FORCE24HOURFORMAT,
  381.                     pstNew, NULL, szTimeNew, sizeof (szTimeNew)) ;
  382.  
  383.      EditPrintf (hwndEdit, 
  384.                  TEXT ("System date and time successfully changed ")
  385.                  TEXT ("from\r\n\t%s, %s.%03i to\r\n\t%s, %s.%03i."), 
  386.                  szDateOld, szTimeOld, pstOld->wMilliseconds,
  387.                  szDateNew, szTimeNew, pstNew->wMilliseconds) ;
  388. }
  389.  
  390. void EditPrintf (HWND hwndEdit, TCHAR * szFormat, ...)
  391. {
  392.      TCHAR   szBuffer [1024] ;
  393.      va_list pArgList ;
  394.  
  395.      va_start (pArgList, szFormat) ;
  396.      wvsprintf (szBuffer, szFormat, pArgList) ;
  397.      va_end (pArgList) ;
  398.  
  399.      SendMessage (hwndEdit, EM_SETSEL, (WPARAM) -1, (LPARAM) -1) ;
  400.      SendMessage (hwndEdit, EM_REPLACESEL, FALSE, (LPARAM) szBuffer) ;
  401.      SendMessage (hwndEdit, EM_SCROLLCARET, 0, 0) ;
  402. }
  403.